/**
 * 
 */
package org.dse.analysis.dict;

import java.util.HashMap;

/**
 * This class represents the nodes in the dictionary. The dictionary stores the
 * word in a tree structure. It begins from a single node as the root. The root
 * stores the first characters of all words. A node has many characters. Each
 * character in a node has many children, which are the next character behind
 * the character in a word.
 * 
 * Each node has a Map data structure. The key indicates the character, and the
 * object associated with it points to a child node, which stores the next
 * character.
 * 
 * @author zhangchen
 * 
 */
public class DictSegment {

	// the data structure
	private HashMap<Character, DictSegment> dictTreeNodeMap;

	private int nodeState;// 1 indicates the node is an end node

	private WordType wordType;

	/**
	 * The default constructor.
	 */
	public DictSegment() {
		nodeState = 0;
		wordType = new WordType();
	}

	/**
	 * Add a word to the tree structure.
	 * 
	 * @param seg
	 *            the char array word to be added
	 * @param wordType
	 *            the word type
	 */
	public void addWord(char seg[], WordType wordType) {
		addWord(seg, 0, seg.length - 1, wordType);
	}

	/**
	 * Add a word, overloading.
	 * 
	 * @param seg
	 *            the char array
	 * @param begin
	 *            the begin offset of the char array to be added
	 * @param end
	 *            the end offset
	 * @param wordType
	 *            the word type
	 */
	public void addWord(char seg[], int begin, int end, WordType wordType) {
		if (dictTreeNodeMap == null)
			dictTreeNodeMap = new HashMap<Character, DictSegment>(2, 0.8F);
		Character keyChar = new Character(seg[begin]);
		DictSegment ds = dictTreeNodeMap.get(keyChar);

		if (ds == null) {// if the char has not been added before in this
			// node
			ds = new DictSegment();
			dictTreeNodeMap.put(keyChar, ds);// add a new entry to the map
		}
		if (begin < end)
			ds.addWord(seg, begin + 1, end, wordType);// use recursive method
		// to add the next char
		// to the child node
		else if (begin == end) {// the whole word is added
			ds.setNodeState(1);
			ds.wordType.addWordType(wordType);
		}
	}

	/**
	 * Search a word from this node.
	 * 
	 * @param seg
	 *            the char array
	 * @param begin
	 *            the begin offset of the char array to be searched
	 * @param end
	 *            the end offset
	 */
	public Hit search(char seg[], int begin, int end) {
		Hit searchHit = new Hit();
		return search(seg, begin, end, searchHit);
	}

	private Hit search(char seg[], int begin, int end, Hit searchHit) {
		if (dictTreeNodeMap == null) {
			searchHit.setUnmatch();
			return searchHit;
		}
		Character keyChar = new Character(seg[begin]);
		DictSegment ds = dictTreeNodeMap.get(keyChar);
		if (ds != null) {// use recursive method to search the next char in
							// the child node
			if (begin < end)
				return ds.search(seg, begin + 1, end, searchHit);
			if (begin == end) {
				if (ds.getNodeState() == 1) {
					searchHit.setMatch();
					searchHit.setWordType(ds.getWordType());
				}
				if (ds.hasNextNode())
					searchHit.setPrefixMatch();
			}
		} else {
			searchHit.setUnmatch();
		}
		return searchHit;
	}

	/**
	 * Judge the node is not an end node.
	 * 
	 * @return a boolean value to show whether it is an end node
	 */
	public boolean hasNextNode() {
		return dictTreeNodeMap != null && !dictTreeNodeMap.isEmpty();
	}

	/**
	 * Get the node state.
	 * 
	 * @return an integer representing the node state
	 */
	public int getNodeState() {
		return nodeState;
	}

	/**
	 * Set the node state.
	 * 
	 * @param nodeState
	 *            the node state
	 */
	public void setNodeState(int nodeState) {
		this.nodeState = nodeState;
	}

	/**
	 * Get the word type, the word ends at the current node.
	 * 
	 * @return the word type
	 */
	public WordType getWordType() {
		return wordType;
	}
}